#include <unistd.h>
#include <stdio.h>
#include <string>
#include "Thread.hpp"
#include "LockGoard.hpp"
std::string GetThreadreturn_name()
{
    static int number = 1;
    char name[64];
    snprintf(name, sizeof(name), "Thread-%d", number++);
    return name;
}
std::string GetThreadName()
{
    static int number = 1;
    char name[64];
    snprintf(name, sizeof(name), "Thread-%d", number++);

    return name;
}
oid Print(int num)
{
    while (num)
    {
        std::cout << "hello world: " << num-- << std::endl;
        sleep(1);
    }
}

int ticket = 10000; // 全局的共享资源
// 共享资源了
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 锁就有了，被定义并初始化了，这个锁也是全局的哦！！

// 加锁：
// 1. 我们要尽可能的给少的代码块加锁
// 2. 一般加锁，都是给临界区加锁
void GetTicket(ThreadData *td)
{
    while (true)
    {
        // 1. 申请锁本身是安全的，原子的
        // 2. 是由程序员自己保证的！规则都必须先申请锁
        // 3. 根据互斥的定义，任何时刻，只允许一个线程申请锁成功！多个线程申请锁失败，失败的线程怎么办？在mutex上进行阻塞，本质就是等待！
        // 4. 一个线程在临界区中访问临界资源的时候，可不可能发生切换?可能，完全允许！！

        // pthread_mutex_lock(&mutex);
        // 临界区代码
        {
            LockGuard lockguard(td->pmutex);
            if (ticket > 0)
            {
                // 充当抢票花费的时间
                usleep(1000);
                printf("%s get a ticket: %d\n", td->threadname, ticket);
                ticket--;
                pthread_mutex_unlock(&mutex);
            }
            else
            {
                // 释放锁
                pthread_mutex_unlock(&mutex);
                break;
            }
        }
    }
}
/*
加锁: pthread_mutex_t
初始化: PTHREAD_MUTEX_INITIALIZER
申请锁:pthread_mutex_lock
释放锁:pthread_mutex_unlock
一般加锁都是给临界区加锁
    多个线程申请锁失败，在mutex上阻塞
pthread_mutex_trylock//判断申请锁是否成功
初始化：
    全局/静态 变量：pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    局部变量：pthread_mutex_init
加锁：原子的
1.尽可能给少的代码加锁
2.一般加锁，都是给临界区加锁
3.个别系统，抢票代码会出现很多票被同一个线程抢完了
4.多线程运行，同一份资源，有线程长时间无法拥有资源，饥饿问题
5.解决这个问题，要让线程有顺序的执行

可重入函数一定是线程安全的
*/
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

/*
死锁：一直占有资源不释放资源，使线程或进程不能向后执行

条件：互斥，请求与保持，循环等待，不剥夺条件
避免死锁：
    破坏死锁的四个条件（一个或多个）
    加锁顺序一致
    避免锁未释放的场景
    资源一次性分配

线程同步

生产者消费者模型
*/
class ThreadData
{
public:
    ThreadData(std::string name.pthread_mutex_t *mutex) : threadname(name),
                                                          pmutex(mutex)
    {
    }

public:
    std::string threadname;
    pthread_mutex_t *pmutex;
};

int main()
{
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, nullptr);

    std::string name1 = GetThreadName();
    ThreadData td1 = new ThreadData(name1, &mutex);
    // Thread<std::string> t1(name1, GetTicket, name1);
    Thread<ThreadData *> t1(name1, GetTicket, name1);

    std::string name2 = GetThreadName();
    ThreadData td2 = new ThreadData(name2, &mutex);
    // Thread<std::string> t2(name2, GetTicket, name2);
    Thread<ThreadData *> t2(name2, GetTicket, name1);

    std::string name3 = GetThreadName();
    ThreadData td3 = new ThreadData(name3, mutex);
    // Thread<std::string> t3(name3, GetTicket, name3);
    Thread<ThreadData *> t3(name3, GetTicket, name1);

    std::string name4 = GetThreadName();
    ThreadData td4 = new ThreadData(name4, mutex);
    // Thread<std::string> t4(name4, GetTicket, name4);
    Thread<ThreadData *> t4(name4, GetTicket, name1);
    t1.Start();
    t2.Start();
    t3.Start();
    t4.Start();

    t1.Join();
    t2.Join();
    t3.Join();
    t4.Join();

    pthread_mutex_destroy(&mutex);
    // std::string name = GetThreadreturn_name();
    // Thread t(Print, name);
    // std::cout << "is thread running "<<t.isrunning() << std::endl;
    // t.start();
    // std::cout << "is thread running "<< t.isrunning() << std::endl;
    // t.join();
    /*

    */
    return 0;
}